package com.y.fund.utils;

import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.spec.SecretKeySpec;

import com.y.fund.consts.ConstAttr;
import com.y.fund.web.aavo.com.LgnUserVo;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import jakarta.xml.bind.DatatypeConverter;

public class JwtUtil{

    /** Signature key customization */
    protected static final String BASE64SECRET = "a546l78Yoleo9t876y5o443l25e66o5e123456765532e";

    /** Timeout milliseconds (default 24 hours) */
    public static final long EXPIRES_MILLIS = 86400000L;

    /** Key customization for JWT encryption */
    public static final String DATAKEY = "CC767461894684409EA2BFA357BA8A5A";

    /**
     * @Description: Generate JWT string; Format: A.B.C
     * A-header info
     * B-payload 
     * C-signature
     * @param lgnId - User login record ID
     */
    public static String CreateUsrIdJWT(String lgnId,  String clientType, String userId, Long expiresMillis) {
        //Signature algorithm, select SHA-256
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
      
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(BASE64SECRET);
     
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
      
        Map<String, Object> headMap = new HashMap<>();
        headMap.put("alg", SignatureAlgorithm.HS256.getValue());
        headMap.put("typ", "JWT");
        
        JwtBuilder builder = Jwts.builder()
        		.setHeader(headMap)
        		.setId(lgnId)
        		.setIssuer(ConstAttr.AUTH_TOKEN_ISSUSER)
        		.setNotBefore(new Date())
                /* Encrypted login record ID */
                .claim("userId", AESUtil.encryptByHexkey(userId, DATAKEY))
                /* User login time */
                .claim("clientType", clientType)
                //Signature
                .signWith(signatureAlgorithm, signingKey);
        
        if(null==expiresMillis) {
        	expiresMillis = EXPIRES_MILLIS;
        }
        
        /* Add token expiration time  */
		long expMillis = System.currentTimeMillis() + expiresMillis;
	 	Date expDate = new Date(expMillis);
	 	builder.setExpiration(expDate);
	 	
        return builder.compact();
    }

    /** Parsing JWT */
    public static LgnUserVo ParseUsrIdByJWT(String jsonWebToken) {
    	LgnUserVo jwtVo = new LgnUserVo();
        Claims claims = null;
        if (StrUtil.NotBlankIgnoreNullStr(jsonWebToken)) {
	        try {
	        	claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(BASE64SECRET)).parseClaimsJws(jsonWebToken).getBody();
	        } catch (ExpiredJwtException e) {
                claims = e.getClaims();
	        } catch (Exception e) {
	        	e.printStackTrace();
	        	System.err.println("Parsing JWT string failed，jsonWebToken：" + jsonWebToken);
	        	e = null;
	        }
        }else {
            System.err.println("[JwtUtil]-json web token is empty.");
        }
        if (claims != null) {
        	if(isTokenExpired(claims)) {
        		jwtVo.setIsExpired(1);
        	}

			jwtVo.setLgnId(claims.getId());
            jwtVo.setUserId(AESUtil.decryptByHexkey((String)claims.get("userId"), DATAKEY));
			jwtVo.setClientType((String)claims.get("clientType"));
			return jwtVo;
        }else {
        	System.err.println("[JwtUtil]- failed to parse the authentication content");
            return null;
        }
    }
    
    /** Determine whether the user session has expired  */
    public static boolean isTokenExpired(Claims claims) {
    	if(null==claims) {
    		return true;
    	}
    	if(null==claims.getExpiration()) {
    		return false;
    	}
        Date expiration = claims.getExpiration();
       
        return new Date(System.currentTimeMillis()).after(expiration);
    }

}